using System;
using System.Collections.Generic;
using System.Data;
using System.Runtime.InteropServices;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Microsoft.SharePoint;
using QueryDemo.ResultProviders;

namespace QueryDemo
{
	[Guid("6b223a13-3d93-4a82-945d-afb91f120ba9")]
	public sealed class QueryDemoWebPart : WebPart
	{
		private bool _error;
		private QueryDemoControl _queryDemoControl;
		private BaseResultProvider _resultProvider;
		private DataTable _resultsTable;

		public QueryType TypeOfQuery { get; set; }
		public string ListTitle { get; set; }
		public int RowLimit { get; set; }

		public QueryDemoWebPart()
		{
			ExportMode = WebPartExportMode.All;
		}

		public override EditorPartCollection CreateEditorParts()
		{
			var editorParts = new List<EditorPart>
			                               	{
			                               		new QueryDemoEditorPart
			                               			{
			                               				ID = ID + "_Editor",
														Title = "Query Demo"
			                               			}
			                               	};
			return new EditorPartCollection(base.CreateEditorParts(), editorParts);
		}

		protected override void CreateChildControls()
		{
			if (!_error)
			{
				try
				{
					base.CreateChildControls();
					
					// Loads user control for display of this web part
					_queryDemoControl = (QueryDemoControl)Page.LoadControl("~/_controltemplates/QueryDemo/QueryDemoControl.ascx");
					Controls.Add(_queryDemoControl);
				}
				catch (Exception ex)
				{
					HandleException(ex);
				}
			}
		}

		protected override void OnLoad(EventArgs e)
		{
			if (!_error)
			{
				try
				{
					// Ensures that the CreateChildControls() is called before events.
					base.OnLoad(e);
					EnsureChildControls();

					// Check things kind of make sense
					if (String.IsNullOrEmpty(ListTitle))
					{
						throw new NullReferenceException("Please configure the web part.");
					}

					// Initialise and execute query and set for display of results
					InitQueryDemo();
					_resultProvider.Init();
					_resultsTable = _resultProvider.ExecuteQuery();
					_queryDemoControl.GridDataSource = _resultsTable;
				}
				catch (Exception ex)
				{
					HandleException(ex);
				}
			}
		}

		private void InitQueryDemo()
		{
			// Get instance to chosen list
			SPList list = SPContext.Current.Web.Lists[ListTitle];

			ConfigureResultProvider(list);

			PopulateRenderControl();
		}

		/// <summary>
		/// Passes through the minimum required to execute a query.
		/// </summary>
		/// <param name="list">List to base results on.</param>
		private void ConfigureResultProvider(SPList list)
		{
			switch (TypeOfQuery)
			{
				case QueryType.ForLoop:
					_resultProvider = new ForLoopResultProvider
					                  	{
					                  		ListTitle = list.Title
					                  	};
					break;
				case QueryType.SPQuery:
					_resultProvider = new SPQueryResultProvider
					                  	{
					                  		ListTitle = list.Title
					                  	};
					break;
				case QueryType.ListsWebService:
					_resultProvider = new ListsWebServiceResultProvider
					                  	{
					                  		ListTitle = list.Title,
											Web = list.ParentWeb
					                  	};
					break;
				case QueryType.PortalSiteMapProvider:
					_resultProvider = new PortalSiteMapResultProvider
					                  	{
					                  		ListTitle = list.Title,
					                  		Web = list.ParentWeb,
					                  		CamlQuery = String.Empty
					                  	};
					break;
				case QueryType.SPSiteDataQuery:
					_resultProvider = new SPSiteDataQueryResultProvider
					                  	{
					                  		ServerTemplate = GetServerTemplate(list),
					                  		Web = list.ParentWeb
					                  	};
					break;
				case QueryType.CrossListQueryInfo:
					_resultProvider = new CrossListQueryInfoResultProvider
										{
											ServerTemplate = GetServerTemplate(list),
											Site = list.ParentWeb.Site,
											CamlQuery = String.Empty
										};
					break;
				//case QueryType.FullTextMossSqlQuery:
				//    _resultProvider = new FullTextSqlMossResultProvider
				//                        {
				//                            Site = SPContext.Current.Site
				//                        };
				//    break;
				//case QueryType.FullTextWssSqlQuery:
				//    _resultProvider = new FullTextSqlWssResultProvider
				//                        {
				//                            Site = SPContext.Current.Site
				//                        };
				//    break;
				// TODO: Query web service
			}
			_resultProvider.ViewFields = list.DefaultView.ViewFields;
			_resultProvider.RowLimit = RowLimit;
		}

		private static int GetServerTemplate(SPList list)
		{
			var listProperties = XElement.Parse(list.PropertiesXml);
			var serverTemplate = listProperties.Attribute("ServerTemplate").Value;
			return int.Parse(serverTemplate);
		}

		/// <summary>
		/// Set values to be displayed to the user.
		/// </summary>
		private void PopulateRenderControl()
		{
			_queryDemoControl.CamlQuery = _resultProvider.CamlQuery;
			_queryDemoControl.CrossSiteCapable = _resultProvider.CrossSiteCapable;
			_queryDemoControl.ListTitle = _resultProvider.ListTitle;
			_queryDemoControl.ListId = _resultProvider.ListId;
			_queryDemoControl.WebId = (_resultProvider.Web != null) ? _resultProvider.Web.ID : Guid.Empty;
			_queryDemoControl.SiteId = (_resultProvider.Site != null) ? _resultProvider.Site.ID : Guid.Empty;
			_queryDemoControl.RowLimit = _resultProvider.RowLimit;
			_queryDemoControl.ServerTemplate = _resultProvider.ServerTemplate;
			_queryDemoControl.TypeOfQuery = _resultProvider.TypeOfQuery;
		}

		/// <summary>
		/// Clear all child controls and add an error message for display.
		/// </summary>
		/// <param name="ex"></param>
		private void HandleException(Exception ex)
		{
			_error = true;
			Controls.Clear();
			Controls.Add(new Label
			             	{
			             		Text = ex.ToString(),
								ForeColor = System.Drawing.Color.Red
			             	});
		}
	}
}
